package cn.org.wifit.imserver.boot;

import cn.org.wifit.imserver.im.handle.UDPServerHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;

/**
 * 为客户端开启netty的UDP服务
 */
public class StartupNettyUDPBoot implements Runnable {
	/**
	 * UDP服务准备的事件环路
	 */
	private EventLoopGroup udpLoopGroup;
	
	/**
	 * UDP服务的启动器
	 */
	private Bootstrap udpBootstrap;
	
	private UDPServerHandler udpServerHandler;
	
	/**
	 * 启动状态：0，表示还没有启动完
	 * 1，表示启动正常完成
	 * 2，启动完成，但是发生异常
	 */
	private Integer bootState = 0;
	
	public StartupNettyUDPBoot() {
		
	}
	
	@Override
	public void run() {
		//这是从本地变量中来的udp port
		String udpPort = BootStartup.LOCAL_Environment.get("-U");
		this.bootState = 0;
		
        try {
        	this.udpBootstrap.group(this.udpLoopGroup)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST, true);
        	this.udpBootstrap.handler(this.udpServerHandler);
        	
            io.netty.channel.ChannelFuture channelFuture = this.udpBootstrap.bind(Integer.parseInt(udpPort)).await();
            this.bootState = 1;
            synchronized (this) {
				this.notify();
			}
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
			e.printStackTrace(System.out);
			this.bootState = 2;
			synchronized (this) {
				this.notify();
			}
		} finally {
			this.udpLoopGroup.shutdownGracefully();
        }
	}
	
	/**
	 * 该方法一旦被调用，调用者线程将会等待，直到UDP连接建立完成（无论建立成功，还是建立失败）
	 */
	public void sync() throws Exception {
		try {
			synchronized (this) {
				while(this.bootState == 0) {
					this.wait();
				}
			}
			
			//如果条件成立，则抛出错误信息
			if(this.bootState == 2) {
				throw new RuntimeException("启动UDP出现错误，请检查机器状态和配置项");
			}
		} catch(Exception e) {
			e.printStackTrace(System.out);
		}
	}

	public EventLoopGroup getUdpLoopGroup() {
		return udpLoopGroup;
	}

	public void setUdpLoopGroup(EventLoopGroup udpLoopGroup) {
		this.udpLoopGroup = udpLoopGroup;
	}

	public Bootstrap getUdpBootstrap() {
		return udpBootstrap;
	}

	public void setUdpBootstrap(Bootstrap udpBootstrap) {
		this.udpBootstrap = udpBootstrap;
	}

	public UDPServerHandler getUdpServerHandler() {
		return udpServerHandler;
	}

	public void setUdpServerHandler(UDPServerHandler udpServerHandler) {
		this.udpServerHandler = udpServerHandler;
	}
} 
